package bcslib

import (
	"fmt"
	"github.com/garyburd/redigo/redis"
	u "lpaiche.com/utils"
	"runtime"
	"strconv"
	"time"
)

type status_struct struct {
	numGoroutine int
}

var (
	rp     *u.RedisPool //redis 连接池
	status status_struct
)

//等待取队列,并实现多协程分布处理
func StartWaitGetBailQueue() {
	u.InitConfig("./conf/bcs_config.toml")
	InitConfig("./conf/bcs_private_config.toml")

	status = status_struct{numGoroutine: 0}
	queueKey := conf.RedisKeys.BailChangeQueue

	if queueKey == "" {
		msg := "配置conf.RedisKeys.BailChangeQueue不正确!"
		fmt.Println(msg)
		u.Panic(msg)
	}

	rp = u.NewRedisPoolFromConfig()
	defer rp.Close()

	for {
		r, err := redis.Strings(rp.Do("BRPOP", queueKey, 0))
		if err != nil {
			u.Trace(err)
			time.Sleep(5000000 * time.Microsecond)
		}
		if len(r) > 0 {
			queueContextJsonStr := r[1]
			StartHanding(queueContextJsonStr)
			continue
		} else {
			time.Sleep(500 * time.Microsecond)
		}
	}

}

//开始指定车商处理协程
func StartSpecDealerId(dealer_id string) {
	u.InitConfig("./conf/bcs_config.toml")
	InitConfig("./conf/bcs_private_config.toml")

	status = status_struct{numGoroutine: 0}
	queueKey := conf.RedisKeys.BailChangeQueue

	if queueKey == "" {
		msg := "配置conf.RedisKeys.BailChangeQueue不正确!"
		fmt.Println(msg)
		u.Panic(msg)
	}

	rp = u.NewRedisPoolFromConfig()
	defer rp.Close()

	_bool := lockHanding(dealer_id)
	if _bool == true {
		handing(dealer_id)
		u.Trace("车商：" + dealer_id + " 处理协程开始")
	} else {
		u.Trace("车商：" + dealer_id + " 处理已在运行")
	}
}

//开始消费队列内容
func StartHanding(queueContextJsonStr string) {
	handingKey := conf.RedisKeys.BailChangeQueueHanding
	if handingKey == "" {
		u.Panic("配置conf.RedisKeys.BailChangeQueueHanding不正确!")
	}
	bqc := JsonStr2BailQueueContext(queueContextJsonStr)

	dealer_id := strconv.FormatInt(bqc.Summary.Dealer_id, 10)
	//存入车商的处理中队列
	_, err := redis.Bool(rp.Do("LPUSH", handingKey+dealer_id, queueContextJsonStr))
	if err != nil {
		u.Panic("LPUSH到" + handingKey + dealer_id + "队列失败!")
	}
	u.Trace("获得车商操作信息：车商ID " + dealer_id)

	//每个车商只开一个协程处理
	_bool := lockHanding(dealer_id)
	if _bool == true {
		go handing(dealer_id)
		u.Trace("车商：" + dealer_id + " 处理协程开始")
	} else {
		u.Trace("车商：" + dealer_id + " 处理已在运行")
	}
}

//锁定一个车商只限一个协程处理
func lockHanding(dealer_id string) (b bool) {
	lockKey := conf.RedisKeys.EnableHandingLock
	if lockKey == "" {
		u.Panic("配置conf.RedisKeys.EnableHandingLock不正确!")
	}
	lockKey = lockKey + dealer_id
	u.Trace(lockKey)
	lock, err := redis.Bool(rp.Do("SETNX", lockKey, 1))
	if err != nil {
		u.Trace(err)
		return false
	}
	return lock

}

//车商队列处理完毕解锁协程
func unLockHanding(dealer_id string) {
	lockKey := conf.RedisKeys.EnableHandingLock + dealer_id
	_, err := rp.Do("DEL", lockKey)
	if err != nil {
		u.Trace("队列完毕协程解锁故障，锁key为:" + lockKey)
		u.Trace(err)
	} else {
		u.Trace("车商:" + dealer_id + "处理完毕")
	}
}

//处理某车商保证金操作队列
func handing(dealer_id string) {

	//处理某车商保证金发生严重异常
	defer func() {
		if errr := recover(); errr != nil {
			u.Trace("车商:" + dealer_id + " 发生严重异常")
			u.Trace(errr)
		}
	}()

	//解除车商协程锁
	defer func() {
		unLockHanding(dealer_id)
		status.numGoroutine--
	}()

	status.numGoroutine++
	u.Trace("runtime协程总数:" + strconv.Itoa(runtime.NumGoroutine()) + "\t其中队列消费协程数：" + strconv.Itoa(status.numGoroutine))
	handingKey := conf.RedisKeys.BailChangeQueueHanding
	handingKey = handingKey + dealer_id

	bf := NewBailFixed()
	defer bf.Close()

	for {
		queueContextJsonStr, err := redis.String(rp.Do("LINDEX", handingKey, -1))
		if err != nil {
			u.Trace(err)
			break
		}
		u.Trace("内容处理,队列key为:" + handingKey)
		u.Trace(queueContextJsonStr)
		bqc := JsonStr2BailQueueContext(queueContextJsonStr)
		u.Trace(bqc)
		insertId := bf.ExecBailQueueContext(&bqc)
		_, err = redis.String(rp.Do("RPOP", handingKey))
		if err != nil {
			u.Trace("清除处理过的内容出错!")
			u.Trace(err)
		}
		u.TraceFile("插入保证金记录:" + strconv.FormatInt(insertId, 10))
	}

	handingComplete(dealer_id)
}

//某车商队列处理完毕
func handingComplete(dealer_id string) {

}
